package pl.wroc.uni.ii.evolution.engine.operators.spacespecific.binaryvector.boa.metrics;

/**
 * 
 * @author Jarek Fuks, Zbigniew Nazimek
 *
 * Bayesian-Dirchlet metric without prior knowlege about problem
 *
 */


import pl.wroc.uni.ii.evolution.engine.EvPopulation;
import pl.wroc.uni.ii.evolution.engine.individuals.EvBinaryVectorIndividual;
import pl.wroc.uni.ii.evolution.engine.operators.spacespecific.binaryvector.boa.bayesnetwork.EvIBayesianNetwork;
import pl.wroc.uni.ii.evolution.engine.operators.spacespecific.binaryvector.boa.utils.EvBinary;

public class EvBayesianDirchletMetric implements EvIMetric<EvBinaryVectorIndividual>{

  public double compute(EvPopulation<EvBinaryVectorIndividual> population, EvIBayesianNetwork<EvBinaryVectorIndividual> network, EvBinary ev_binary) {
    double value = 0.0;
    int number_of_nodes = population.get(0).getDimension();
    
    for (int i = 0;i < number_of_nodes; i++) {
      int[] parents_indexes = network.getParentsIndexes(i);
      int[] all_indexes = new int[parents_indexes.length + 1];
      
      for (int n = 0; n < parents_indexes.length; n++) {
        all_indexes[n] = parents_indexes[n];
      }
      all_indexes[all_indexes.length - 1] = i;
            
      
      //this can be optimalised
      double sub_value = 0.0;
      for(int k = 0; k < EvBinary.pow2(parents_indexes.length); k++) {
        boolean[] parents_value = EvBinary.intToBools(k, parents_indexes.length);
        boolean[] all_value = EvBinary.intToBools(k, parents_indexes.length + 1);
        
        all_value[all_value.length - 1] = false;
        int m_parents = EvBinary.numberOf(population,parents_value,parents_indexes);
        int m_false = EvBinary.numberOf(population,all_value,all_indexes);
        all_value[all_value.length - 1] = true;
        int m_true = EvBinary.numberOf(population,all_value,all_indexes);
        
        sub_value += ev_binary.sumLogFromMap(1+m_true);
        sub_value += ev_binary.sumLogFromMap(1+m_false);
        sub_value -= ev_binary.sumLogFromMap(1+m_parents);
               
      }
      value += sub_value;
    }
    return value;
  }

}
